﻿using System;
using System.Configuration;
using OdsServer.Common.Enum;

namespace OdsServer.Common
{
    public sealed class OdsServerConfiguration : ConfigurationSection, IServerConfiguration
    {
        private static volatile OdsServerConfiguration selfRef = null;
        private static bool readOnly;

        private OdsServerConfiguration() { }

        public static OdsServerConfiguration GetInstance()
        {
            if (selfRef == null)
            {
                selfRef = LoadSection();
            }
            return selfRef;
        }

        [ConfigurationProperty("marshalTransfer",
            IsDefaultCollection = true)]
        public OdsServerMarshalConfiguration MarshalTransfer
        {
            get { return (OdsServerMarshalConfiguration)base["marshalTransfer"]; }
        }

        [ConfigurationProperty("pipeTransfer",
            IsDefaultCollection = true)]
        public OdsServerPipeConfiguration PipeTransfer
        {
            get { return (OdsServerPipeConfiguration)base["pipeTransfer"]; }
        }

        [ConfigurationProperty("socketTransfer",
            IsDefaultCollection = true)]
        public OdsServerSocketConfiguration SocketTransfer
        {
            get { return (OdsServerSocketConfiguration)base["socketTransfer"]; }
        }

        private static OdsServerConfiguration LoadSection()
        {
            object section = null;

            try
            {
                section = ConfigurationManager.GetSection("serverSetupParams");
            }
            catch(Exception e)
            {
                throw new ConfigurationErrorsException("OdsServerConfiguration is invalid: " + e.Message);
            }
            if (section == null)
            {
                throw new ConfigurationErrorsException("OdsServerConfiguration is missing.");
            }
            return (OdsServerConfiguration)section;
        }

        public SetupParameters GetSetupParameters()
        {
            SetupParameters result = new SetupParameters();

            lock (this)
            {
                result.baseChannelNumber    = (ushort)this.BaseChannelNumber;
                result.channelCount         = (ushort)this.ChannelCount;
                result.defaultDataType      = this.DefaultDataType;
                result.timeInterval         = this.TimeInterval;
                result.useMarshalTransfer   = this.UseMarshalTransfer;
                result.usePipeTransfer      = this.UsePipeTransfer;
                result.useSocketTransfer    = this.UseSocketTransfer;
                result.parentWindowHanlde   = IntPtr.Zero;
            }

            return result;
        }

        private new bool IsReadOnly
        {
            get
            {
                return readOnly;
            }
        }

        protected override object GetRuntimeObject()
        {
            readOnly = true;
            return base.GetRuntimeObject();
        }

        public bool UseMarshalTransfer
        {
            get { return this.MarshalTransfer.Active; }
            set { this.MarshalTransfer.Active = value; }
        }

        public bool UsePipeTransfer
        {
            get { return this.PipeTransfer.Active; }
            set { this.PipeTransfer.Active = value; }
        }

        public bool UseSocketTransfer
        {
            get { return this.SocketTransfer.Active; }
            set { this.SocketTransfer.Active = value; }
        }

        [ConfigurationProperty("baseChannelNumber",
            DefaultValue = 0,
            IsRequired = true,
            IsKey = false)]
        [IntegerValidator(MinValue = 0, MaxValue = 15, ExcludeRange = false)]
        public int BaseChannelNumber
        {
            get { return (int)this["baseChannelNumber"]; }
            set { this["baseChannelNumber"] = value; }
        }

        [ConfigurationProperty("channelCount",
            DefaultValue = 1,
            IsRequired = true,
            IsKey = false)]
        [IntegerValidator(MinValue = 1, MaxValue = 16, ExcludeRange = false)]
        public int ChannelCount
        {
            get { return (int)this["channelCount"]; }
            set { this["channelCount"] = value; }
        }

        [ConfigurationProperty("timeInterval",
            DefaultValue = 2,
            IsRequired = true,
            IsKey = false)]
        [IntegerValidator(MinValue = 0, MaxValue = 1000000, ExcludeRange = false)]
        public int TimeInterval
        {
            get { return (int)this["timeInterval"]; }
            set { this["timeInterval"] = value; }
        }

        [ConfigurationProperty("defaultDataType",
            DefaultValue = ChannelDataType.Binary,
            IsRequired = true,
            IsKey = false)]
        public ChannelDataType DefaultDataType
        {
            get { return (ChannelDataType)this["defaultDataType"]; }
            set { this["defaultDataType"] = value; }
        }
    }
}
